home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / UTIL / MEMORY / VIRTUASRC / !Virtual / c / pager < prev    next >
Text File  |  1993-09-06  |  13KB  |  522 lines

  1. /*
  2.  * pager.c
  3.  * Part of the !Virtual distribution
  4.  * (c) bdb/nas/fo, 1992-3
  5.  */
  6.  
  7. #include "swis.h"
  8. #include "swiv.h"
  9. #include "wimp.h"
  10.  
  11. #include "virtual.h"
  12. #include "lib.h"
  13. #include "output.h"
  14. #include "pager.h"
  15.  
  16. /* #define DEBUG */
  17.  
  18. void Initourmem(WKSP *w)
  19. {
  20.   int i;
  21.   w->stacktop = (char *)alloc(STACKSIZE)+STACKSIZE;
  22.  
  23.   swi(OS_ReadMemMapInfo, OUT(R0|R1), &w->pagesize, &w->numpages);
  24.  
  25.   w->pageshift = 15;
  26.   if (w->pagesize == K32/2) w->pageshift = 14;
  27.   if (w->pagesize == K32/4) w->pageshift = 13;
  28.  
  29.   w->numplaces = PLACE(M24);
  30.   w->ourmem = alloc(sizeof(int) * w->numplaces);
  31.  
  32.   w->oldpages = alloc(sizeof(PAGEENTRY)*(w->numpages + 1));
  33.   w->newpages = alloc(sizeof(PAGEENTRY)*(w->numpages + 1));
  34.   FindPages(w);
  35.  
  36.   w->nslots = 0;        /* page file empty */
  37.   w->index = alloc(sizeof(int)*w->numplaces);
  38.  
  39.   for ( i=PLACE(K32); i<w->numplaces; i++)
  40.   { w->ourmem[i] = TAGLOC(ABORT, 0);
  41.   }
  42.   w->losepage = 0;
  43. }
  44.  
  45. void SetWimpMemMap(WKSP *w)
  46. {
  47.   int i;
  48. #ifdef DEBUG
  49.   printf("Places %d..%d match wimp map\n",PLACE(K32),w->numourpages+PLACE(K32));
  50. #endif
  51.   for ( i = 0; i<w->numourpages; i++ )
  52.   { w->newpages[i].addr = ADDR(i)+K32;
  53.     w->newpages[i].access = ACCESS_READWRITE;
  54.     w->ourmem[i+PLACE(K32)] = TAGLOC(DIRTY,i);
  55.   }
  56.   for ( i=w->numourpages+PLACE(K32); i<w->numplaces; i++ )
  57.     w->ourmem[i] = TAGLOC(ABORT, 0);
  58.   for (i=0;i<w->nslots;i++)
  59.     w->index[i] = -1;
  60. }
  61.  
  62. void Finishourmem(WKSP *w)
  63. {
  64.   free(w->oldpages);
  65.   free(w->newpages);
  66.   free(w->ourmem);
  67.   free(w->index);
  68. }
  69.  
  70. int SetVirtualSlot(WKSP *w, int size)
  71. { int i,m;
  72.   i = PLACE(K32);
  73.   m = i + PLACE(size);
  74. #ifdef DEBUG
  75.   printf("Places %d..%d abort->zerofill\n",i,m);
  76. #endif
  77.   for (;i<m;i++)
  78.     if (TAG(w->ourmem[i])==ABORT)
  79.       w->ourmem[i] = TAGLOC(ZERO,0);
  80.   return size;
  81. }
  82.  
  83.  
  84. void virtualmem(WKSP *w)
  85. {
  86.   swi(OS_SetMemMapEntries, IN(R0), w->newpages);
  87. }
  88.  
  89. void normalmem(WKSP *w)
  90. {
  91.   swi(OS_SetMemMapEntries, IN(R0), w->oldpages);
  92. }
  93.  
  94. /* Find us a set of pysical pages, preserving newpages[0..numourpages].addr,access */
  95.  
  96. void FindPages(WKSP *w)
  97. {
  98.   int i;
  99.   int appspace;
  100.   int a, b;
  101.   for (i = 0; i<w->numpages ; i++)
  102.     w->oldpages[i].pagenum = i;
  103.   w->oldpages[w->numpages].pagenum = -1;
  104.   swi(OS_ReadMemMapEntries, IN(R0), w->oldpages);
  105.   swi(OS_ChangeEnvironment, IN(R0|R1)|OUT(R1), 14, 0, &appspace);
  106.   w->numourpages = PLACE(appspace - K32);
  107.   b = w->numourpages;   /* We accumulate pages that must be moved out the way here */
  108.   for (i = 0; i<w->numpages; i++)
  109.   { if (w->oldpages[i].addr < K32)              /* OS workspace will get protected */
  110.       /*w->newpages[b++] = w->oldpages[i] */;
  111.     else if (w->oldpages[i].addr < appspace)    /* Useable page */
  112.     { a = PLACE(w->oldpages[i].addr-K32);       /* its current place */
  113.       w->newpages[a].pagenum = i;               /* it becomes our page */
  114.     }
  115.     else if (w->oldpages[i].addr < M24)         /* page needs moving */
  116.       w->newpages[b++] = w->oldpages[i];
  117.   }
  118.   for (i=0; i<w->numourpages; i++)
  119.   { w->oldpages[i].pagenum = w->newpages[i].pagenum;
  120.     w->oldpages[i].addr = ADDR(i)+K32;
  121.     w->oldpages[i].access = ACCESS_READWRITE;
  122.   }
  123.   for (i = w->numourpages; i<b; i++)
  124.   { w->oldpages[i] = w->newpages[i];
  125.     if (w->newpages[i].addr<K32)
  126.       w->newpages[i].access = ACCESS_READONLY;
  127.     else
  128.     { w->newpages[i].addr = DUMPADDR;
  129.       w->newpages[i].access = ACCESS_BAD;
  130.   } }
  131.   w->oldpages[b].pagenum = -1;
  132.   w->newpages[b].pagenum = -1;
  133. }
  134.  
  135. static int pageout(WKSP *w, int page, int addr)
  136. {
  137.   int place, Normaddr, slot;
  138.   place = PLACE(addr);
  139.   Normaddr = w->oldpages[page].addr;
  140.   slot = LOC(w->ourmem[place]);
  141.   switch (TAG(w->ourmem[place]))
  142.   { case DIRTY:
  143.       for (slot = 0; slot<w->nslots; slot++)
  144.         if (w->index[slot] == -1)
  145.           break;
  146.       if (slot>=w->nslots)
  147.       { w->nslots = slot+1;
  148. #ifdef DEBUG
  149.         printf("nslots = %d\n",w->nslots);
  150. #endif
  151.       }
  152.       swi(OS_GBPB, IN(R0|R1|R2|R3|R4), 1, w->pagefile, Normaddr, w->pagesize, ADDR(slot));
  153.       /* FALL THROUGH */
  154.     case SAVED:
  155.       w->index[slot] = place;
  156.       w->ourmem[place] = TAGLOC(PAGED, slot);
  157.       break;
  158.     default:
  159.       printf("*** ILLEGAL page out tag page %d addr %d place %d Normaddr %d slot %d tag %d\n",
  160.                 page,addr,place,Normaddr,slot,TAG(w->ourmem[place]));
  161.       RealDoOff(w);
  162.       break;
  163.   }
  164. #ifdef DEBUG
  165.   printf("Paging place %d out from page %d to slot %d\n",place,page,slot);
  166. #endif
  167.   return page;
  168. }
  169.  
  170. static int findpageout(WKSP *w)
  171. {
  172.   int addr, page;
  173. loop:
  174.   page = w->losepage;
  175.   if (++w->losepage >= w->numourpages)
  176.     w->losepage = 0;
  177.   addr = w->newpages[page].addr;
  178.   if (addr == DUMPADDR)
  179.     return page;
  180.   if (addr & LOCKADDRBIT)
  181.     goto loop;
  182.   return pageout(w,page,addr);
  183. }
  184.  
  185. static void pagein(WKSP *w, int page, int place, int write)
  186. { int Normaddr = w->oldpages[page].addr;
  187.   int slot = LOC(w->ourmem[place]);
  188.   swi(OS_GBPB, IN(R0|R1|R2|R3|R4), 3, w->pagefile, Normaddr, w->pagesize, ADDR(slot));
  189.   w->newpages[page].addr = ADDR(place);
  190.   if (write)
  191.   { w->newpages[page].access = ACCESS_READWRITE;
  192.     w->index[slot] = -1;
  193.     w->ourmem[place] = TAGLOC(DIRTY, page);
  194.   }
  195.   else
  196.   { w->newpages[page].access = ACCESS_READONLY;
  197.     w->index[slot] = page;
  198.     w->ourmem[place] = TAGLOC(SAVED, slot);
  199.   }
  200. #ifdef DEBUG
  201.   printf("Paging place %d in to page %d from slot %d %s",place,page,slot,write?"writeable":"readonly");
  202. #endif
  203. }
  204.  
  205. /*
  206.  * First page out all DIRTY places whose address is not as RISC OS expects
  207.  * Then page in all place which should be in that page.
  208.  */
  209. void FixMemoryPages(WKSP *w)
  210. {
  211.   int i;
  212.   for (i = 0; i < w->numourpages; i++)
  213.     if (w->newpages[i].addr != ADDR(i) + K32 &&
  214.         w->newpages[i].access != ACCESS_BAD)
  215.       switch (TAG(w->ourmem[PLACE(w->newpages[i].addr)])) {
  216.         case DIRTY:
  217.           pageout(w, i, w->newpages[i].addr);
  218.           break;
  219.       } /* switch */
  220.   for (i = 0; i < w->numourpages; i++) {
  221.     if (w->newpages[i].addr != ADDR(i) + K32) {
  222.       switch (TAG(w->ourmem[i+PLACE(K32)])) {
  223.         case PAGED:
  224.           pagein(w, i, i + PLACE(K32), 1);
  225.           break;
  226.         case ZERO:
  227. /*
  228.  * This page was just recieved from the wimp by a wimplsot drag.
  229.  * I'm not really sure if the tag, the place recieves here 
  230.  * should be DIRTY; maybe ZERO is ok. But, to be consistent with Brian's
  231.  * code in SetWimpMemMap, all places paged in at the right page,
  232.  * get the DIRTY tag.
  233.  */
  234.           w->ourmem[i+PLACE(K32)] = TAGLOC(DIRTY, i);
  235.           w->newpages[i].addr = ADDR(i) + K32;
  236.           w->newpages[i].access = ACCESS_READWRITE;
  237.           break;
  238.       } /* switch */
  239.     }
  240.   }
  241. }
  242.  
  243. void SetRealMem(WKSP*w, int size)
  244. {
  245.   int newnumourpages=PLACE(size);
  246.   int i,newslot;
  247.   if (newnumourpages<2)
  248.     newnumourpages=2;
  249.   if (newnumourpages!=w->numourpages)
  250.   { for (i = newnumourpages; i < w->numourpages; i++)
  251.     {
  252.       if (w->newpages[i].addr!=DUMPADDR)
  253.         pageout(w, i, w->newpages[i].addr);
  254.     }
  255.     swi(Wimp_SlotSize,IN(R0|R1)|OUT(R0),ADDR(newnumourpages),-1,&newslot);
  256.     newnumourpages = PLACE(newslot);
  257.     for (i = w->numourpages; i<newnumourpages; i++)
  258.     { w->newpages[i].addr=DUMPADDR;
  259.       w->newpages[i].access=ACCESS_BAD;
  260.     }
  261.  
  262. /*
  263.  * When the user drags our slotbar, we often will receive more than one
  264.  * wimp_MSETSLOT message at once. In the old code, w->losepage would then
  265.  * be set at the *end* of a big block of DUMPADDR pages. This is a waste.
  266.  * The code below ensures w->losepage is always on the first DUMPADDR page.
  267.  */
  268.     if (w->numourpages < newnumourpages) {
  269.       for (i = 0; i < newnumourpages; i++)
  270.         if (w->newpages[i].addr == DUMPADDR) {
  271.            w->losepage = i;
  272.            break;
  273.         }
  274.     }
  275.     else
  276.       w->losepage = 0;
  277.     w->numourpages = newnumourpages;
  278.  
  279.   #ifdef DEBUG
  280.     printf("numourpages=%d\n",newnumourpages);
  281.   #endif
  282. } }
  283.  
  284. static int GetPlace(WKSP *w, int place, int write)
  285. { int page,slot;
  286.   page = LOC(w->ourmem[place]);
  287.   switch (TAG(w->ourmem[place]))
  288.   {
  289.     case SAVED:
  290.       slot = page;
  291.       page = w->index[slot];
  292.       if (!write)
  293.         return page;
  294.       w->newpages[page].access = ACCESS_READWRITE;
  295.       w->index[slot] = -1;
  296.       w->ourmem[place]=TAGLOC(DIRTY,page);
  297. #ifdef DEBUG
  298. printf("Dirtying place %d in page %d free slot %d\n",place,page,slot);
  299. #endif
  300.       if ( slot == w->nslots-1 ) /* last slot in file freed */
  301.       { while (slot>=0 && w->index[slot]==-1)
  302.           slot--;
  303.         w->nslots = slot+1;
  304.         swi(OS_Args,IN(R0|R1|R2),3,w->pagefile,ADDR(w->nslots));
  305. #ifdef DEBUG
  306.         printf("nslots down = %d\n",w->nslots);
  307. #endif
  308.       }
  309.       return page;
  310.     case PAGED:
  311.       page=findpageout(w);
  312.       pagein(w, page, place, write);
  313.       return page;
  314.     case ZERO:
  315.       page=findpageout(w);
  316.       w->ourmem[place] = TAGLOC(DIRTY, page);
  317.       w->newpages[page].addr = ADDR(place);
  318.       w->newpages[page].access = ACCESS_READWRITE;
  319. #ifdef DEBUG
  320. printf("Place %d gets page %d zeroed",place,page);
  321. #endif
  322.       return page;
  323.     case DIRTY:
  324.       return page;
  325.     case ABORT:
  326.       printf("***ABORT: place %d\n",place);
  327.       return -1;
  328.     default:
  329.       printf("***ILLEGAL tag: place %d in page %d tag %d\n",place,page,TAG(w->ourmem[place]));
  330.       RealDoOff(w);
  331.       return -1;
  332.   }
  333. }
  334.  
  335. static int VGetPlace(WKSP *w, int place, int write)
  336. { int page;
  337.   switch (TAG(w->ourmem[place]))
  338.   { case DIRTY:
  339.       return LOC(w->ourmem[place]);
  340.     case SAVED:
  341.       if (!write)
  342.         return LOC(w->ourmem[place]);
  343.     default:
  344.       Normal(w);
  345.       page = GetPlace(w,place,write);
  346.       Virtual(w);
  347.       return page;
  348.   }
  349. }
  350.  
  351. RANGE Locate(WKSP *w, int start, int end)
  352. { int place,page;
  353.   RANGE r;
  354. #ifdef DEBUG
  355.   printf("Locate: %x-%x",start,end);
  356. #endif
  357.   if (start<K32)
  358.     return r.start=start,r.end=end<K32?end:K32,r;
  359.   if (start>=M24)
  360.     return r.start=start,r.end=end,r;
  361.   place=PLACE(start);
  362.   page=LOC(w->ourmem[place]);
  363.   switch (TAG(w->ourmem[place]))
  364.   {
  365.     case DIRTY:
  366.     case SAVED:
  367.       r.start=w->oldpages[page].addr+SHUFT(start);
  368.       break;
  369.     case ZERO:
  370.       r.start = 0;
  371.       break;
  372.     case ABORT:
  373.       r.start = -1;
  374.       break;
  375.     case PAGED:
  376.       r.start = (1u<<31) + ADDR(page) + SHUFT(start);
  377.       break;
  378.   }
  379.   r.end = r.start + w->pagesize - SHUFT(start);
  380.   if (r.end>r.start+end-start)
  381.     r.end = r.start+end-start;
  382. #ifdef DEBUG
  383.   printf("==>%x-%x\n",r.start,r.end);
  384. #endif
  385.   return r;
  386. }
  387.  
  388. RANGE Physical(WKSP *w, int start, int end)
  389. { int place,page;
  390.   RANGE r;
  391. #ifdef DEBUG
  392.   printf("Physical: %x-%x",start,end);printflush(w);
  393. #endif
  394.   if (end<start)
  395.     RealDoOff(w);
  396.   if (start<K32)
  397.     return r.start=start,r.end=end<K32?end:K32,r;
  398.   if (start>=M24)
  399.     return r.start=start,r.end=end,r;
  400.   place=PLACE(start);
  401.   page=GetPlace(w,place,1);
  402.   if (page==-1)
  403.     return r.start=0,r.end=0,r;
  404.   r.start=w->oldpages[page].addr+SHUFT(start);
  405.   r.end = w->oldpages[page].addr+w->pagesize;
  406.   if (r.end>r.start+end-start)
  407.     r.end = r.start+end-start;
  408. #ifdef DEBUG
  409.   printf("==>%x-%x\n",r.start,r.end); printflush(w);
  410. #endif
  411.   return r;
  412. }
  413.  
  414. int ToMem(WKSP *w, void *src, int dest, int size)
  415. { RANGE r;
  416.   int l;
  417.   while (size>0)
  418.   { r = Physical(w, dest, dest+size);
  419.     if (!r.end)
  420.       return 0;
  421.     l=r.end-r.start;
  422.     memcpy((void*)r.start,src,l);
  423.     src=(char*)src+l;
  424.     dest+=l;
  425.     size-=l;
  426.   }
  427.   return 1;
  428. }
  429.  
  430. int FromMem(WKSP *w, int src, void *dest, int size)
  431. { RANGE r;
  432.   int l;
  433.   while (size>0)
  434.   { r = Physical(w, src, src+size);
  435.     if (!r.end)
  436.       return 0;
  437.     l=r.end-r.start;
  438.     memcpy(dest,(void *)r.start,l);
  439.     src+=l;
  440.     dest=(char*)dest+l;
  441.     size-=l;
  442.   }
  443.   return 1;
  444. }
  445.  
  446.  
  447. /* Called in virtual, svc mode to ensure range all accessable */
  448.  
  449. int ReadRange(WKSP *w, int start, int end)
  450. {
  451.   int place1,place2,page1,page2;
  452.   if (start<K32)
  453.     return 0;
  454.   if (start>=M24)
  455.     return 1;
  456.   if (end>M24)
  457.     end=M24;
  458.   place1 = PLACE(start);
  459.   place2 = PLACE(end-1);
  460.   page1=VGetPlace(w,place1,0);
  461.   if (page1==-1)
  462.     return 0;
  463.   if (place2!=place1)
  464.   { w->newpages[page1].addr |= LOCKADDRBIT;
  465.     page2 = VGetPlace(w,place2,0);
  466.     w->newpages[page1].addr &= ~LOCKADDRBIT;
  467.     if (page2==-1)
  468.       return 0;
  469.   }
  470.   return 1;
  471. }
  472.  
  473. int WriteRange(WKSP *w, int start, int end)
  474. {
  475.   int place1,place2,page1,page2;
  476.   if (start<K32)
  477.     return 0;
  478.   if (start>=M24)
  479.     return 1;
  480.   if (end>M24)
  481.     end=M24;
  482.   place1 = PLACE(start);
  483.   place2 = PLACE(end-1);
  484.   page1=VGetPlace(w,place1,1);
  485.   if (page1==-1)
  486.     return 0;
  487.   if (place2!=place1)
  488.   { w->newpages[page1].addr |= LOCKADDRBIT;
  489.     page2 = VGetPlace(w,place2,1);
  490.     w->newpages[page1].addr &= ~LOCKADDRBIT;
  491.     if (page2==-1)
  492.       return 0;
  493.   }
  494.   return 1;
  495. }
  496.  
  497. int ReadPtr(WKSP *w, int start)
  498. { int place,page;
  499.   if (start<K32)
  500.     return 0;
  501.   if (start>=M24)
  502.     return 1;
  503.   place = PLACE(start);
  504.   page=VGetPlace(w,place,0);
  505.   if (page==-1)
  506.     return 0;
  507.   return 1;
  508. }
  509.  
  510. int WritePtr(WKSP *w, int start)
  511. { int place,page;
  512.   if (start<K32)
  513.     return 0;
  514.   if (start>=M24)
  515.     return 1;
  516.   place = PLACE(start);
  517.   page=VGetPlace(w,place,1);
  518.   if (page==-1)
  519.     return 0;
  520.   return 1;
  521. }
  522.